﻿using Sidvall.Business;
using System.Collections.Generic;
using System.ComponentModel;

namespace Sidvall.Data
{
    public abstract class SimpleServiceDataRowBase : IDataRowContextProvider, IOnPropertyChanged, IBusinessSettingsProvider, INotifyPropertyChanged,
        INotifyDataErrorInfo, IBusinessRulesProvider
    {
        #region Public Members

        public event System.EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
        public event PropertyChangedEventHandler PropertyChanged;

        // Protected
        #region BusinessSettings

        private System.Lazy<BusinessSettings> _BusinessSettings = new System.Lazy<BusinessSettings>(BusinessSettings.CreateSettingsNone);
        protected BusinessSettings BusinessSettings
        {
            get
            {
                return _BusinessSettings.Value;
            }
        }

        #endregion
        #region DataRowBusinessRules

        private BusinessRuleCollection _DataRowBusinessRules;
        protected BusinessRuleCollection DataRowBusinessRules
        {
            get
            {
                if (_DataRowBusinessRules == null)
                {
                    lock (_Mutex)
                    {
                        if (_DataRowBusinessRules == null)
                        {
                            var items = new BusinessRuleCollection();
                            items.BusinessRulePropertyChanged += OnDataRowBusinessRulesPropertyChanged;
                            _DataRowBusinessRules = items;
                        }
                    }
                }
                return _DataRowBusinessRules;
            }
        }

        #endregion

        #region GetDataRowBusinessRulesForProperty

        protected virtual BusinessRuleCollection GetDataRowBusinessRulesForProperty(string propertyName)
        {
            var items = new BusinessRuleCollection();
            if (!string.IsNullOrWhiteSpace(propertyName))
                items.AddRange(true, this.DataRowBusinessRules.FindBusinessRulesForProperties(true, propertyName));
            else
                items.AddRange(true, this.DataRowBusinessRules.FindBusinessRulesForProperties(true));
            return items;
        }

        #endregion
        #region OnDataRowBusinessRulesPropertyChanged

        protected void OnDataRowBusinessRulesPropertyChanged(object sender, BusinessRulePropertyEventArgs e)
        {
            if (e == null)
                throw new System.ArgumentNullException(nameof(e));
            _ClearErrors = true;
            foreach (var propertyName in e.PropertyNames)
                OnErrorsChanged(propertyName);
            _ClearErrors = false;
            foreach (var propertyName in e.PropertyNames)
                OnErrorsChanged(propertyName);
        }

        #endregion
        #region OnErrorsChanged

        protected void OnErrorsChanged(string propertyName)
        {
            OnErrorsChanged(new DataErrorsChangedEventArgs(propertyName));
        }
        protected virtual void OnErrorsChanged(DataErrorsChangedEventArgs args)
        {
            if (this.BusinessSettings.EnabledBusinessEvents.HasFlag(BusinessEvents.NotifyErrorsChanged))
            {
                if (this.ErrorsChanged != null)
                    this.ErrorsChanged.Invoke(this, args);
            }
        }

        #endregion
        #region OnPropertyChanged

        protected void OnPropertyChanged(string propertyName)
        {
            OnPropertyChanged(propertyName, true);
        }
        protected void OnPropertyChanged(string propertyName, bool raisePropertyChanged)
        {
            OnPropertyChanged(new PropertyChangedEventArgs(propertyName), raisePropertyChanged);
        }
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs args, bool raisePropertyChanged)
        {
            if ((raisePropertyChanged) && (this.BusinessSettings.EnabledBusinessEvents.HasFlag(BusinessEvents.NotifyPropertyChanged)))
            {
                if (this.PropertyChanged != null)
                    this.PropertyChanged.Invoke(this, args);
            }
        }

        #endregion

        #region IBusinessRulesProvider Members

        BusinessRuleCollection IBusinessRulesProvider.BusinessRules
        {
            get
            {
                return this.DataRowBusinessRules;
            }
        }

        #endregion
        #region IBusinessSettingsProvider Members

        BusinessSettings IBusinessSettingsProvider.BusinessSettings
        {
            get
            {
                return this.BusinessSettings;
            }
        }

        #endregion
        #region IDataRowContextProvider Members

        string IDataRowContextProvider.DataRowContextKey
        {
            get
            {
                return null;
            }
            set
            {
            }
        }
        string IDataRowContextProvider.DataRowContextStorageKey
        {
            get
            {
                return null;
            }
        }

        bool IDataRowContextProvider.DataRowStateIsDeleted
        {
            get
            {
                return false;
            }
        }
        bool IDataRowContextProvider.DataRowStateIsDirty
        {
            get
            {
                return false;
            }
        }
        bool IDataRowContextProvider.DataRowStateIsSelfDirty
        {
            get
            {
                return false;
            }
        }
        bool IDataRowContextProvider.DataRowStateIsNew
        {
            get
            {
                return false;
            }
        }

        void IDataRowContextProvider.SetDataRowContext(IDataRowContextProvider item, DataRowState? dataRowState)
        {
        }
        void IDataRowContextProvider.SetDataRowContext(IDataRowContextProvider item, DataRowState? dataRowState, string dataRowKey)
        {
        }

        #endregion
        #region INotifyDataErrorInfo Members

        System.Collections.IEnumerable INotifyDataErrorInfo.GetErrors(string propertyName)
        {
            if (_ClearErrors)
                return null;
            var items = GetDataRowBusinessRulesForProperty(propertyName);
            if (items.Count == 0)
                return null;
            var value = new List<BusinessRuleCollection>();
            value.Add(items);
            return value;
        }
        bool INotifyDataErrorInfo.HasErrors
        {
            get
            {
                return this.DataRowBusinessRules.Count > 0;
            }
        }

        #endregion
        #region IOnPropertyChanged Members

        void IOnPropertyChanged.OnPropertyChanged(string propertyName, bool raisePropertyChanged, bool updateState)
        {
            OnPropertyChanged(propertyName, raisePropertyChanged);
        }

        #endregion

        #endregion
        #region Private Members

        private readonly object _Mutex = new object();
        private bool _ClearErrors = false;

        #endregion
        #region Constructors

        protected SimpleServiceDataRowBase()
        {
        }

        #endregion
    }
}
